/*
 * compile using:
 * gcc -Wall -Wextra packet.c `pkg-config --cflags opencv` `pkg-config --libs opencv` -o packet.exe
 */
#include "packet.h"

/*
 * makes packet for sending to client
 */
unsigned char* get_rtp_packet(video_manager* cv, unsigned int frame_num,
		unsigned int cseq_num) {
	// size of packet is suffix + header + payload
	//               =   4    +   12   + cv->encoded->cols
	if (get_frame(cv, frame_num)) {
		// error
		return NULL ;
	}
	unsigned char *packet = (unsigned char*) malloc(
			sizeof(unsigned char) * (cv->encoded->cols + 16));
	memset(packet, 0, cv->encoded->cols + 16);
	// make prefix: 0x2400XXXX, where 0xXXXX is size of packet
	// size of packet = size of paylod + size of header (12 bytes)
	// 0x24 = $, bit-shifted into most significant position
	unsigned long packet_size = cv->encoded->cols + 12;
	//printf("size of frame: %d\n", cv->encoded->cols);

	unsigned char buf[4];
	buf[0] = (unsigned char) 0x24;
	buf[1] = (unsigned char) 0x00;
	buf[2] = (unsigned char) ((packet_size >> 8) & 0x000000ff);
	buf[3] = (unsigned char) (packet_size & 0x000000ff);
	// make header
	// attributes: 0x00 0x00 0x00 0x00
	unsigned char attrs[4];
	//attrs[0] = (2 << 6); // version = 2, other fields = 0
	//attrs[1] = JPEG; // payload type

	//attrs[0] = |ver	|ver	|P	|X	|CC	|CC	|CC	|CC
	// = 		 1		0		0	0	0	0	0	0
	unsigned int sequence_num = cseq_num + frame_num;

	attrs[0] = (unsigned char) 0x80;
	attrs[1] = (unsigned char) JPEG; // payload type
	attrs[2] = (unsigned char) (sequence_num >> 8);
	attrs[3] = (unsigned char) sequence_num;
	printf("SeqNum %u %u", attrs[2], attrs[3]);

	// timestamp
	unsigned int timestamp = frame_num * INTERVAL_MS;
	unsigned char time[4];
	time[0] = (unsigned char) (timestamp >> 24);
	time[1] = (unsigned char) (timestamp >> 16);
	time[2] = (unsigned char) (timestamp >> 8);
	time[3] = (unsigned char) timestamp;
	//printf("Time %u %u %u %u", time[0], time[1], time[2], time[3]);

	set_buffer(packet, buf, 4);
	set_buffer(packet + 4, attrs, 4);
	set_buffer(packet + 8, time, 4);
	set_buffer_to(packet + 12, 0, 4); //dummy SSRC
	set_buffer(packet + 16, cv->encoded->data.ptr, cv->encoded->cols);

	return packet;
}

void set_buffer(unsigned char* to, unsigned char* from, unsigned long bytes) {
	unsigned long x = 0;
	unsigned char* current_to = to;

	for (x = 0; x < bytes; x++) {
		*(current_to++) = from[x];
	}
}

void set_buffer_to(unsigned char* to, unsigned char from, unsigned long bytes) {
	unsigned long x = 0;
	unsigned char* current_to = to;

	for (x = 0; x < bytes; x++) {
		*(current_to++) = from;
	}
}

/*
 * initializes video_manager struct, opens file
 * returns 1 on error, 0 on success
 */
// function moved to inside of init_timer() in fsm
int init_video_manager(video_manager* cv, char* filename) {
	cv->image = (IplImage *) malloc(sizeof(IplImage));

	CvMat *thumb = (CvMat *) malloc(sizeof(CvMat));
	thumb = cvCreateMat(HEIGHT, WIDTH, CV_8UC3);
	cv->thumb = thumb;

	cv->encoded = (CvMat *) malloc(sizeof(CvMat));

	cv->video = cvCaptureFromFile(filename);
	if (!cv->video) {
		// The file doesn't exist or can't be captured as a video file.
		perror("could not open file");
		return 1;
	}
	return 0;
}

/*
 * gets frame from video
 * returns 1 on error, 0 on success
 * TODO: remove frame_num dependency, since that function does not work
 */
int get_frame(video_manager* cv, int frame_num) {
	// Position the video at a specific frame number position
	// NOTE: PROBABLY DOES NOT DO ANYTHING
	cvSetCaptureProperty(cv->video, CV_CAP_PROP_POS_FRAMES, frame_num);
	cv->image = cvQueryFrame(cv->video);
	if (!cv->image) {
		// Next frame doesn't exist or can't be obtained.
		perror("bad frame");
		return 1;
	}
	// use thumb to resize
	cvResize(cv->image, cv->thumb, CV_INTER_AREA);
	// Encode the frame in JPEG format with JPEG quality 30%.
	static const int encodeParams[] = { CV_IMWRITE_JPEG_QUALITY, 60 };
	cv->encoded = cvEncodeImage(".jpeg", cv->thumb, encodeParams);
	// After the call above, the encoded data is in encoded->data.ptr
	// and has a length of encoded->cols bytes.
	return 0;
}

/*
 * closes video
 */
void close_video(video_manager* cv) {
	cvReleaseCapture(&cv->video);
}

/*
 * for testing
 */

int main2() {

	char* filename = "sample.avi";
	video_manager *cv = (video_manager*) malloc(sizeof(video_manager));

	// set up cv
	cv->image = (IplImage *) malloc(sizeof(IplImage));
	cv->thumb = cvCreateMat(HEIGHT, WIDTH, CV_8UC3);
	cv->encoded = (CvMat *) malloc(sizeof(CvMat));
	cv->video = cvCaptureFromFile(filename);
	if (!cv->video) {
		// The file doesn't exist or can't be captured as a video file.
		perror("bad file");
		return 1;
	}

	unsigned char* packet = get_rtp_packet(cv, 20, 564);
	if (!packet) {
		perror("could not get packet");
		return 1;
	}

	// start parsing packet, yo
	int i;

	printf("parsed prefix: 0x");
	for (i = 0; i < 4; i++) {
		printf("%x,", (unsigned char) packet[i] & 0xff);
	}
	printf("\n");

	printf("parsed attrs: 0x");
	for (i = 0; i < 4; i++) {
		printf("%x,", (unsigned char) packet[4 + i] & 0xff);
	}
	printf("\n");

	printf("parsed timestamp: 0x");
	for (i = 0; i < 4; i++) {
		printf("%x,", (unsigned char) packet[8 + i] & 0xff);
	}
	printf("\n");

	printf("parsed ssrc: 0x");
	for (i = 0; i < 4; i++) {
		printf("%x,", (unsigned char) packet[12 + i] & 0xff);
	}
	printf("\n");

	close_video(cv);

	return 0;
}

